package com.hmy.contract.service.contract.create.supply;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hmy.ccp.common.result.FeignResult;
import com.hmy.contract.bo.request.oss.OssFileUploadRequest;
import com.hmy.contract.bo.response.oss.OssFileUploadResponse;
import com.hmy.contract.common.constant.ContractConstants;
import com.hmy.contract.common.utils.OssFilePathUtil;
import com.hmy.contract.commons.enums.ContractStatusEnum;
import com.hmy.contract.dal.mapper.ContractMapper;
import com.hmy.contract.dal.mapper.SupplyContractMapper;
import com.hmy.contract.dal.po.ContractPo;
import com.hmy.contract.dal.po.SupplyContractPo;
import com.hmy.contract.manager.order.SupplyOrderFeignClientManager;
import com.hmy.contract.manager.signature.SignatureFeignClientManager;
import com.hmy.contract.service.contract.create.IContractCreateService;
import com.hmy.contract.service.dto.contract.ContractRevokeDto;
import com.hmy.contract.service.dto.contract.FieldDto;
import com.hmy.contract.service.dto.contract.SignTaskDto;
import com.hmy.contract.service.oss.IOssService;
import com.hmy.contract.service.rdto.ContractActorDetailRdto;
import com.hmy.contract.service.rdto.ContractConfigRdto;
import com.hmy.contract.service.rdto.CreateContractRdto;
import com.hmy.contract.service.rdto.SupplyContractRdto;
import com.hmy.infrastructure.api.bo.request.signature.*;
import com.hmy.infrastructure.api.bo.response.signature.CreateSignatureProcessApiResponse;
import com.hmy.infrastructure.api.bo.response.signature.GetSignFileUrlApiResponse;
import com.hmy.infrastructure.api.bo.response.signature.GetSignTaskUrlApiResponse;
import com.hmy.order.api.bo.request.SupplyOrderSignContractRequest;
import com.hmy.order.api.bo.request.UpdateSupplyOrderContractRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author seven.qi 齐胜南
 * @version 1.0
 * @description
 * @date 2023/12/23 16:12
 */
@Service
@Slf4j
public class ElectronicSupplyContractCreateService implements IContractCreateService {

    @Value("${process.definition.id}")
    private String processDefinitionId;

    @Resource
    private SignatureFeignClientManager signatureFeignClientManager;

    @Resource
    private SupplyContractMapper supplyContractMapper;

    @Resource
    private IOssService ossService;

    @Resource
    private SupplyOrderFeignClientManager supplyOrderFeignClientManager;

    @Resource
    private ContractMapper contractMapper;

    @Override
    public String create(CreateContractRdto createContractDto) {
        CreateSignatureProcessApiRequest createSignatureProcessApiRequest = convertToRequest(createContractDto);
        FeignResult<CreateSignatureProcessApiResponse> createSignatureProcessApiResponseJsonResult = signatureFeignClientManager.create(createSignatureProcessApiRequest);
        return createSignatureProcessApiResponseJsonResult.getData().getSignTaskId();
    }

    private CreateSignatureProcessApiRequest convertToRequest(CreateContractRdto dto) {
        ContractConfigRdto configRdto = dto.getContractConfigRdto();
        CreateSignatureProcessApiRequest createSignatureProcessApiRequest = new CreateSignatureProcessApiRequest();
        createSignatureProcessApiRequest.setCreatorPhone(dto.getCreatorPhone());
        createSignatureProcessApiRequest.setSignTemplateId(dto.getSignTemplateId());
        createSignatureProcessApiRequest.setSealId(configRdto.getSealId());
        createSignatureProcessApiRequest.setBusinessId(configRdto.getBusinessId());
        createSignatureProcessApiRequest.setTaskSubject(dto.getTaskSubject());
        createSignatureProcessApiRequest.setTransReferenceId(String.valueOf(dto.getBusinessType()));
        Map<String, List<ContractActorDetailRdto>> actorMap = dto.getContractActorDetailList().stream().collect(Collectors.groupingBy(ContractActorDetailRdto::getActorType));
        ContractActorDetailRdto actorDetailRdto = actorMap.get(ContractConstants.PERSON).get(0);
        List<AuthorizerInfoApi> list = new ArrayList<>();
        AuthorizerInfoApi authorizerInfo = new AuthorizerInfoApi();
        authorizerInfo.setName(actorDetailRdto.getActorName());
        authorizerInfo.setPhone(actorDetailRdto.getAccountName());
        authorizerInfo.setIdCardNo(actorDetailRdto.getCertNoForMatch());
        list.add(authorizerInfo);
        createSignatureProcessApiRequest.setAuthorizerInfoList(list);
        return createSignatureProcessApiRequest;
    }

    @Override
    public List<FieldDto> fillFieldValue(CreateContractRdto createContractDto) {
        List<FieldDto> fieldList = new ArrayList<>();
        Map<String, Object> fieldMap = createContractDto.getFieldMap();
        for (String key : fieldMap.keySet()) {
            fieldList.add(FieldDto.builder().key(key).value(fieldMap.get(key).toString()).build());
        }
        return fieldList;
    }

    @Override
    public String start(String signTaskId, List<FieldDto> fieldDtoList, CreateContractRdto dto) {

        List<FieldApi> fieldApiList = BeanUtil.copyToList(fieldDtoList, FieldApi.class);

        SignTemplateFieldFillApiRequest signTemplateFieldFillApiRequest = new SignTemplateFieldFillApiRequest();
        signTemplateFieldFillApiRequest.setFieldList(fieldApiList);
        signTemplateFieldFillApiRequest.setSignTemplateId(dto.getSignTemplateId());
        signTemplateFieldFillApiRequest.setSignTaskId(signTaskId);
        signatureFeignClientManager.signTemplateFieldFill(signTemplateFieldFillApiRequest);


        StartSignatureProcessApiRequest startSignatureProcessApiRequest = new StartSignatureProcessApiRequest();
        startSignatureProcessApiRequest.setSignTaskId(signTaskId);
        signatureFeignClientManager.start(startSignatureProcessApiRequest);


        GetSignTaskUrlApiRequest getSignTaskUrlApiRequest = new GetSignTaskUrlApiRequest();
        getSignTaskUrlApiRequest.setSignTaskId(signTaskId);
        FeignResult<GetSignTaskUrlApiResponse> signTaskUrl = signatureFeignClientManager.getSignTaskUrl(getSignTaskUrlApiRequest);

        return signTaskUrl.getData().getSignTaskUrl();
    }

    @Override
    public void beforeCreate(CreateContractRdto dto) {

    }

    @Override
    public void afterCreate(CreateContractRdto dto) {
        SupplyContractRdto supplyContractRdto = dto.getSupplyContractRdto();
        SupplyContractPo contractPo = new SupplyContractPo();
        contractPo.setStatus(ContractStatusEnum.WAITING_SIGN.getStatus());
        contractPo.setContractTaskId(supplyContractRdto.getContractTaskId());
        SignTaskDto signTaskDto = new SignTaskDto();
        signTaskDto.setContractSignTaskUrl(dto.getUrl());
        contractPo.setContractSignTaskUrl(JSONUtil.toJsonStr(signTaskDto));
        LambdaQueryWrapper<SupplyContractPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SupplyContractPo::getSupplyContractId, supplyContractRdto.getSupplyContractId());
        wrapper.eq(SupplyContractPo::getIsDeleted, Boolean.FALSE);
        supplyContractMapper.update(contractPo, wrapper);
        // 调用增补订单侧接口，返回增补合同的id和编号
        try {
            UpdateSupplyOrderContractRequest request = new UpdateSupplyOrderContractRequest();
            request.setSupplyContractId(supplyContractRdto.getSupplyContractId());
            request.setSupplyContractNo(supplyContractRdto.getSupplyContractNo());
            request.setSupplyOrderId(supplyContractRdto.getSupplyOrderId());
            supplyOrderFeignClientManager.updateSupplyOrderContract(request);
        } catch (Throwable e) {
            log.error("update supply order contract exception", e);
        }
    }

    @Override
    public Long notify(ContractRevokeDto dto) {
        LambdaQueryWrapper<SupplyContractPo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SupplyContractPo::getContractTaskId, dto.getSignTaskId());
        lambdaQueryWrapper.eq(SupplyContractPo::getIsDeleted, Boolean.FALSE);
        SupplyContractPo supplyContractRo = supplyContractMapper.selectOne(lambdaQueryWrapper);

        String path = "";

        try {
            path = saveSignedFile(supplyContractRo);
        } catch (Exception e) {
            log.error("save signed file exception", e);
        }

        if (StrUtil.isNotEmpty(path)) {
            try {
                path = saveSignedFileToOss(path, supplyContractRo.getSupplyContractNo());
            } catch (Exception e) {
                log.error("save signed file to oss exception", e);
            }
        }
        // 调用增补回调接口
        SupplyOrderSignContractRequest request = new SupplyOrderSignContractRequest();
        request.setSupplyOrderId(supplyContractRo.getSupplyOrderId());
        try {
            supplyOrderFeignClientManager.supplyOrderSignContract(request);
        } catch (Throwable throwable) {
            log.error("supply order sign contract exception", throwable);
        }
        LambdaQueryWrapper<SupplyContractPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SupplyContractPo::getSupplyContractId, supplyContractRo.getSupplyContractId());
        wrapper.eq(SupplyContractPo::getIsDeleted, Boolean.FALSE);
        SupplyContractPo supplyContractPo = new SupplyContractPo();
        supplyContractPo.setStatus(ContractStatusEnum.SIGNED.getStatus());
        supplyContractPo.setContractSignFileUrl(path);
        supplyContractPo.setSignTime(LocalDateTime.now());
        supplyContractMapper.update(supplyContractPo, wrapper);

        // 增补合同签署完成后，更新主合同的hasSupply字段为1
        ContractPo contractPo = new ContractPo();
        contractPo.setHasSupply(1);
        contractPo.setUpdaterName("system");
        contractPo.setUpdateTime(LocalDateTime.now());
        LambdaQueryWrapper<ContractPo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractPo::getContractId, supplyContractRo.getContractId());
        queryWrapper.eq(ContractPo::getIsDeleted, Boolean.FALSE);
        contractMapper.update(contractPo, queryWrapper);
        return supplyContractPo.getSupplyContractId();
    }

    private String saveSignedFileToOss(String path, String contractNo) {
        String storePath = OssFilePathUtil.createElectronicContractPath(contractNo);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        HttpUtil.download(path, outputStream, true);
        OssFileUploadRequest ossFileUploadRequest = new OssFileUploadRequest();
        ossFileUploadRequest.setInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
        ossFileUploadRequest.setStorePath(storePath);
        OssFileUploadResponse ossFileUploadResponse = ossService.ossFileUploadByStream(ossFileUploadRequest);
        return ossFileUploadResponse.getOssPrefix();
    }

    private String saveSignedFile(SupplyContractPo contractPo) {
        GetSignFileUrlApiRequest getSignFileUrlApiRequest = new GetSignFileUrlApiRequest();
        getSignFileUrlApiRequest.setSignTaskId(contractPo.getContractTaskId());
        FeignResult<GetSignFileUrlApiResponse> signFileUrl = signatureFeignClientManager.getSignFileUrl(getSignFileUrlApiRequest);
        return signFileUrl.getData().getSignFileUrl();
    }
}
